package com.gopay.cashier.web.controller.T00100;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import com.gopay.common.constants.SubAccountConstants;
import com.gopay.common.constants.txncd.IntTxnCd;
import com.gopay.common.cps.dao.order.CpsGeneralReceiptOrderQueryDAO;
import com.gopay.common.cps.dao.trans.CpsReceiptSplitDtlQueryDAO;
import com.gopay.common.domain.cps.CpsGenReceiptOrder;
import com.gopay.common.domain.cps.CpsReceiptSplitDtl;
import com.gopay.remote.cps.expresspay.EpBankCardRemoteService;
import com.gopay.remote.order.Tran01813OrderCheckAndUpdateRemoteService;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.gopay.cashier.common.exception.WebException;
import com.gopay.cashier.domain.bean.LoginUser;
import com.gopay.cashier.service.riskcontrol.CallRiskControlService;
import com.gopay.cashier.web.command.ExpressPayChannelCommand;
import com.gopay.cashier.web.command.ExpressPoundageVo;
import com.gopay.cashier.web.utils.BisBankBusinessProdConvertUtil;
import com.gopay.common.Result;
import com.gopay.common.cipher.utils.LoggerMaskUtils;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.constants.bank.ExPayBankConstants;
import com.gopay.common.constants.cust.CustPersonInfoConstants;
import com.gopay.common.constants.ep.EpCardType;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.constants.trans.OrderFeePayer;
import com.gopay.common.constants.trans.PayChannel;
import com.gopay.common.constants.trans.TxnStaCode;
import com.gopay.common.domain.acps.AcctStatus;
import com.gopay.common.domain.acps.FrezCode;
import com.gopay.common.domain.acps.model.AcctMastBean;
import com.gopay.common.domain.bank.ExPayBaseMessage;
import com.gopay.common.domain.bank.PayResult;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.cust.CustPersonInfo;
import com.gopay.common.domain.ep.EpCardBin;
import com.gopay.common.domain.ep.EpCardBindInfo;
import com.gopay.common.domain.pg.PgGenOrderTransDtl;
import com.gopay.common.domain.poundage.PoundageRes;
import com.gopay.common.exception.GopayException;
import com.gopay.common.proccode.DicProcCodeService;
import com.gopay.common.util.DateUtils;
import com.gopay.common.util.RequestUtils;
import com.gopay.remote.order.MainOrderField;

import net.sf.json.JSONObject;


/**
 * Created by HJY on 2015/5/7.
 * 未登录--快捷支付
 */
@Controller
@RequestMapping("/00100/express")
public class ExpressPayChannelController extends ExpressBaseController {
    //生产优化14期修改 手机号只判断以1开头
    private static Pattern mobileNo = Pattern.compile("^1\\d{10}$");

    //private static final String VAL_BROWSER_VERSION_NUMBER = "8.0.7600.16385";//鉴权接口需要浏览器版本号，可以置为死值，暂时取IE8的

    @Autowired
    private CpsGeneralReceiptOrderQueryDAO cpsGeneralReceiptOrderQueryDAO;

    @Autowired
    private CpsReceiptSplitDtlQueryDAO cpsReceiptSplitDtlQueryDAO;

    @Resource(name="callRiskControlService")
    private CallRiskControlService callRiskControlService;
    @Resource(name="dicProcCodeService")
    private DicProcCodeService dicProcCodeService;

    @Resource(name = "epBankCardService")
    private EpBankCardRemoteService epBankCardRemoteService;



    @Resource(name = "tran01813OrderCheckAndUpdateService")
    private Tran01813OrderCheckAndUpdateRemoteService tran01813OrderCheckAndUpdateRemoteService;
    
    @RequestMapping("/location.shtml")
    public ModelAndView locationPayChannel(ExpressPayChannelCommand exCommand) throws GopayException{
        try {
            prepareRSA();
        } catch (Exception e) {
            throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002);
        }
        printRequest("expressPayChannelController-location");
        String orderId = getRequest().getParameter(GOPAY_ORDER_ID);
        CpsGenMainOrder order = getMainOrder(orderId, true);

        decrypt4js(exCommand);

        validate(order,exCommand);

        //防钓鱼校验
        ModelAndView check = checkAntiPhish(exCommand,"/00100/express/location.shtml?orderKey="+getRequest().getParameter("orderKey")+"&orderId="+orderId);
        if(check != null)
            return check;

        String cardNo = exCommand.getBankCardNo().replaceAll(" ","");
        ModelAndView mv = new ModelAndView("/00100/content/express/firstPay");
        mv.addObject("bankCardNo", cardNo);
        mv.addObject("hideBankCardNo",getHiddenCardNo(exCommand.getBankCardNo()));
        mv.addObject("exPayBankCode",exCommand.getExPayBankCode());
        mv.addObject("exPayChannel",exCommand.getExPayChannel());
        mv.addObject("orderId",orderId);
        mv.addObject("order", getOrderInfo(orderId));
        
        
        //快捷支付  身份验证版  update  by dongdh 20160318
        PgGenOrderTransDtl transDtl = pgGeneralOrderTransDtlQueryManager.get(order.getTransDtlSq());
        
        if (StringUtils.isNotBlank(transDtl.getBuyerRealName()) 
        		&& StringUtils.isNotBlank(transDtl.getBuyerRealCertNo())) {
        	///同时有  才在页面显示, 单传一个字段 不做校验
        	mv.addObject("exHolder", transDtl.getBuyerRealName());
            mv.addObject("exIdCardNo", transDtl.getBuyerRealCertNo());
            mv.addObject("hidExHolder", getHiddenExHolder(transDtl.getBuyerRealName()));
            mv.addObject("hidExIdCardNo", getHiddenExIdCardNo(transDtl.getBuyerRealCertNo()));
            
            /*if (!PayChannel._03.value.equals(exCommand.getExPayChannel())) {
            	//快捷身份验证版 不支持 信用卡付款
            	logger.info("快捷支付验证版 不支持 信用卡付款orderId=" + orderId);
            	throw new WebException(ProcCodeConstants.PROC_CODE_100E6085);
            }*/
        }
        
        if (StringUtils.isNotBlank(transDtl.getBuyerRealBankAcctNum())) {
        	//快捷身份验证版 不支持 信用卡付款
        	
        	/*if (!PayChannel._03.value.equals(exCommand.getExPayChannel())) {
        		logger.info("快捷支付验证版 不支持 信用卡付款orderId=" + orderId);
            	throw new WebException(ProcCodeConstants.PROC_CODE_100E6085);
            }*/
        	
        	//判断两次卡号 是否一致cardNo
        	if (!StringUtils.equals(cardNo, transDtl.getBuyerRealBankAcctNum())) {
        		/**
        		 * modified by zyt 对日志卡号做掩码显示
        		 * 2017-1-13
        		 */
        		logger.info("提交卡号与上送卡号不一致：上送卡号=" + LoggerMaskUtils.maskString(transDtl.getBuyerRealBankAcctNum()) + ", 提交卡号=" + LoggerMaskUtils.maskString(cardNo));
        		//logger.info("提交卡号与上送卡号不一致：上送卡号=" + transDtl.getBuyerRealBankAcctNum() + ", 提交卡号=" + cardNo);
        		throw new WebException(ProcCodeConstants.PROC_CODE_100E6084);
        	}
        	
        	if (StringUtils.isNotEmpty(transDtl.getBuyerRealBankAcctNum())) {
        		if (getLoginUser() != null) {
        			SecurityUtils.getSubject().logout();
        		}
        	}
        }
        
        mv.addObject("exMobileNo", transDtl.getBuyerRealMobile());
        
        return mv;
    }

    @RequestMapping("/exfp.shtml")
    public ModelAndView exfp(ExpressPayChannelCommand exCommand) throws GopayException{
        decrypt4js(exCommand);
        printRequest("expressPayChannelController-exfp");
        String orderId = getRequest().getParameter(GOPAY_ORDER_ID);
        CpsGenMainOrder order = getMainOrder(orderId, true);
        
        //统一校验
        validate(order,exCommand);

        //快捷校验
        checkExpress(exCommand);
        
        //方案校验
        checkSolution(exCommand, order);
        
        
        //校验快捷短信验证码令牌  add by fanghw 20160514
        checkEpSmsToken(orderId,exCommand.getBankCardNo());
        
        
        
        
        //快捷支付 身份验证版  update by dongdh 20160318
        PgGenOrderTransDtl transDtl = pgGeneralOrderTransDtlQueryManager.get(order.getTransDtlSq());
        validateExpressAuthentication(transDtl, exCommand, false);
        EpCardBindInfo bindInfo=null;
        
        //一个身份证最多5个用户的验证(不包括未实名未认证用户,"01":身份证，"0":未实名未认证)
        List<CustPersonInfo> custPersonList = custPersonInfoQueryManager.findByCustListBycertNo("01", exCommand.getExIdCardNo(),"0");
        if(custPersonList.size()<5){
        	 //创建用户并绑定卡--返回为空 未绑定
           bindInfo = bindCardInfo(exCommand, order);
            
        }
        //更新订单状态
        updateOrder(exCommand,order,bindInfo == null ? null :bindInfo.getCustId());

        /**** add by sh.jiao 20170920 增加云账户子账户收款修改关联订单交易金额，手续费金额等字段更新逻辑 start ****/
        /*if(IntTxnCd._01813.value.equals(order.getGopayIntTxnCd())) {
            String resultCode = tran01813OrderCheckAndUpdateRemoteService.checkAndUpdateOrder(order.getGopayOrderId());
            if (!ProcCodeConstants.PROC_CODE_000S1000.equals(resultCode)) {
                throw new GopayException(resultCode);
            }
        }*/
        /**** add by sh.jiao 20170920 增加云账户子账户收款修改关联订单交易金额，手续费金额等字段更新逻辑 end ****/

        order = getMainOrder(orderId, true);
        //风控校验
        //rimsProcess(order);

        //调用风控二期服务校验 add by xuhui 20160811
        ModelAndView mv = callRiskControl(order, exCommand);
        if(mv != null){
            return mv;
        }

        //新额度校验前置更新银行卡号
        updatePayOrder(orderId, exCommand.getBankCardNo());

        //发起快捷支付请求
        PayResult result = exPayRemoteService.pay(getPayRequest(orderId,getExCommand(exCommand,bindInfo)));
        if(result != null){
            logger.info("express pay orderId:"+orderId+" res:"+result.isSuccess()+" resCode:"+result.getResultCode());
        }

        return  new ModelAndView("redirect:/00100/express/progress.shtml?orderKey="+getRequest().getParameter("orderKey")+"&t="+(bindInfo != null ? bindInfo.getSq() : 0)+"&orderId="+orderId);
    }

    @RequestMapping("/getSms.shtml")
    @ResponseBody
    public String sendSms(ExpressPayChannelCommand exCommand,String orderId) throws Exception {

        JSONObject json = new JSONObject();
        String err = null;
        try {
            decrypt4js(exCommand);

            CpsGenMainOrder order = getMainOrder(orderId, true);
            
            //校验是否满十八岁  add by gaocl ----20170405
            String ageCheckErr = checkAgeToken(exCommand.getExIdCardNo());
            if(null != ageCheckErr ){
                err = ageCheckErr;
                throw new Exception("您还未满18周岁，无法继续支付！");
            }
            
            //支付鉴权
            ExPayBaseMessage message = getExPayBaseMessage(order,exCommand);
            //===start 应银行封装接口的要求鉴权之前先验证短信，所以传入一下两个参数， modify by liuyong 20161221
            message.setSenMaxCount(5);
            message.setFailMaxCount(5);
            //===end
            //logger.info("快捷支付发短信前，支付鉴权的参数为:"+ToStringBuilder.reflectionToString(message));
            logger.error("鉴权之前结算金额1 settle = " + message.getSettleAmt());
            Result result = exAuthRemoteService.certification(message);
            logger.error("鉴权之前结算金额2 settle = " + message.getSettleAmt());
            //Result result =bisCertificationRemoteService.cardCertification(message);
            if(result != null){
                logger.info("auth orderId:"+orderId+" res:"+result.isSuccess()+" resCode:"+result.getResultCode() +" retMsg:"+result.getModel("retMsg")+ " resFlag:"+result.getModel("flag"));
                if(result.isSuccess() && ((boolean) result.getModel("flag"))){
                    message.setSenMaxCount(5);
                    message.setFailMaxCount(5);
                    message.setSmsContent(getSmsContent(order,exCommand));
                    //发送短信
                    logger.error("发短信之前结算金额1 settle = " + message.getSettleAmt());
                    result = exAuthRemoteService.sendSms(message);
                    logger.error("发短信之前结算金额2 settle = " + message.getSettleAmt());
                    if(result != null){
                        String sendCount = (String)result.getModel("sendCount");
                            /**start ---卡号日志掩码处理 ssj 2017-04-18*/
                           logger.info("send sms orderId:"+orderId+" for mobileNo:"+LoggerMaskUtils.maskString(exCommand.getExMobileNo())+" sendCount:"+sendCount+" res:"+result.isSuccess()+" resCode:"+result.getResultCode() +" retMsg:"+result.getModel("retMsg")+ " resFlag:"+result.getModel("flag"));
                            /**end*/
                            if(result.isSuccess()){
                            if(((boolean) result.getModel("flag"))){
                                json.accumulate("result","1");
                            }else{
                            	json.accumulate("retMsg",(String)result.getModel("retMsg"));
                            }
                        }
                    }
                }else if(ProcCodeConstants.PROC_CODE_100E6100.equals((String)result.getResultCode())
                		||ProcCodeConstants.PROC_CODE_100E6094.equals((String)result.getResultCode())
                		||ProcCodeConstants.PROC_CODE_100E6095.equals((String)result.getResultCode())){
                	json.accumulate("retMsg",dicProcCodeService.getProcCodeInfo((String)result.getResultCode()).getMessage());
                }else{
                    //银行卡信息有误，验证码发送失败
                    err = "2";
                }
            }else{
                logger.error("send sms orderId:"+orderId+" error: result is null");
            }
        }catch(GopayException ex){
        	json.accumulate("retMsg",dicProcCodeService.getProcCodeInfo(ex.getErrCode()).getMessage());
        } catch (Exception e) {
            logger.error("send sms orderId:"+orderId+" error:"+e.getMessage());
            e.printStackTrace();
        }
        json.accumulate("errMsg",err);
        return json.toString();
    }

    @RequestMapping("/checkSms.shtml")
    @ResponseBody
    public String checkSms(ExpressPayChannelCommand exCommand,String orderId){

        JSONObject json = new JSONObject();
        try {
            decrypt4js(exCommand);
            CpsGenMainOrder order = getMainOrder(orderId, true);
            ExPayBaseMessage message = getExPayBaseMessage(order,exCommand);
            message.setValidateCode(exCommand.getExSmsCode());
            message.setFailMaxCount(5);
            message.setTimeOut("600");//短信有效期10分钟
            //logger.info("未登录发起支付时，验短信的参数为:"+ToStringBuilder.reflectionToString(message));
            //短信校验
            Result result = exAuthRemoteService.checkSms(message);
            if(result != null){
                String failCount = (String)result.getModel("failCount");
                /**start ---手机号日志掩码处理 ssj 2017-04-18*/
                logger.info("check sms orderId:"+orderId+" for mobileNo:"+LoggerMaskUtils.maskString(exCommand.getExMobileNo())+" failCount:"+failCount+" res:"+result.isSuccess()+" resCode:"+result.getResultCode() +" retMsg:"+result.getModel("retMsg")+ " resFlag:"+result.getModel("flag"));
                /**end*/
                if(result.isSuccess()){
                    if(((boolean) result.getModel("flag"))){
                        //生成快捷短信验证码令牌  add by fanghw 20160514
                        generateEpSmsToken(orderId,message.getCardNo());
                       
                        json.accumulate("result","1");
                    }else{
                        json.accumulate("failCount",new Integer(failCount));
                        json.accumulate("retMsg",(String)result.getModel("retMsg"));
                        //epBankCardService.errAccum4SMS(exCommand.getBankCardNo());
                    }
                }else{
                    String retErrCode = result.getResultCode();
                    if(ProcCodeConstants.PROC_CODE_100E6103.equals(retErrCode)){
                        json.accumulate("retMsg","请重新获取短信验证码");
                    }else if(ProcCodeConstants.PROC_CODE_100E6104.equals(retErrCode)){
                        String errorMsg = dicProcCodeService.getProcCodeInfo((String)result.getResultCode()).getMessage();
                        if(StringUtils.isNotBlank(errorMsg)){
                            json.accumulate("retMsg",errorMsg);
                        }else{
                            json.accumulate("retMsg","银行卡信息有误，请仔细核对");
                        }
                    }else{
                        json.accumulate("retMsg",dicProcCodeService.getProcCodeInfo((String)result.getResultCode()).getMessage());
                    }
                }
            }else{
            	  /**start ---卡号日志掩码处理 ssj 2017-04-18*/
                logger.error("check sms orderId:"+orderId+" for mobileNo:"+LoggerMaskUtils.maskString(exCommand.getExMobileNo())+" result is null ");
                /**end*/
            }
        }catch(GopayException ex){
        	json.accumulate("retMsg",dicProcCodeService.getProcCodeInfo(ex.getErrCode()).getMessage());
        } catch (Exception e) {
            logger.error("check sms orderId:"+orderId+" error:"+e.getMessage());
        }
        return json.toString();
    }

    private ExPayBaseMessage getExPayBaseMessage(CpsGenMainOrder order,ExpressPayChannelCommand command) throws GopayException{
        ExPayBaseMessage base = new ExPayBaseMessage();
        base.setBank(command.getExPayBankCode());
        base.setOrderId(order.getGopayOrderId());
        base.setAmount(order.getMerTxnAmt());
        base.setBankBusProd(BisBankBusinessProd._15);
        base.setMediaId(command.getExMobileNo());
        base.setCardNo(command.getBankCardNo());
        base.setCardHolder(command.getExHolder());
        base.setIdentityCode(command.getExIdCardNo());
        // 快捷支付改造修改  update by dhj at 20161201 start
        if(StringUtils.isBlank(base.getCardHolder())&&StringUtils.isBlank(base.getIdentityCode())){
    		LoginUser oprInfo = (LoginUser) SecurityUtils.getSubject().getPrincipal();
    		if(null == oprInfo){
    			logger.error("快捷支付时，session失效。。。。。。未取到登录用户信息");
    			throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002);
    		}
    		String custId = oprInfo.getUser().getCustId();
    		CustPersonInfo personInfo = custPersonInfoQueryManager.get(custId);
        	base.setCardHolder(personInfo.getCustName());
        	base.setIdentityCode(personInfo.getCertNo());
        }
        // 快捷支付改造修改  update by dhj at 20161201 end
        base.setIdentityType(CustPersonInfoConstants.CERT_TYPE_IDCARD);
        if(StringUtils.equals(order.getPayChannel(),PayChannel._06.toString()) || StringUtils.equals(command.getExPayChannel(),PayChannel._06.toString())){
            base.setCvv2(command.getExCvn2());
            //二次支付查询有效期  add by liuyong
            if(StringUtils.isBlank(command.getExCardId())){
                base.setAvailableDate(command.getExValidDate());
            }else{
                EpCardBindInfo cardInfo = epBankCardRemoteService.getCardInfoById(command.getExCardId());
                base.setAvailableDate(cardInfo.getCreditCardExpired());
            }
            // end
            base.setBankOrderType(BisBankBusinessProdConvertUtil.getBisBankBusinessProd(PayChannel.get(command.getExPayChannel())).value);
            base.setBankBusProd(BisBankBusinessProd._05);
        }
        base.setBrowser(ExPayBankConstants.VAL_BROWSER_VERSION_NUMBER);
        base.setUserIp(RequestUtils.getRemoteRealIpAddr(getRequest()));
        base.setTermination(ExPayBankConstants.TERMINAL_TYPE_PC);

        //==start增加结算金额参数 add by liuyong 20170110
        ExpressPoundageVo epv = getPoundageRes(order,command);
        PoundageRes p = epv.getPoundageRes();
        logger.error("鉴权之前，发短信之前，计算结算金额 settleAmt = " + p.getSettleAmt().toPlainString());
        base.setSettleAmt(p.getSettleAmt().toPlainString());
        //==end
        return  base;
    }



    private void checkExpress(ExpressPayChannelCommand exCommand)throws GopayException {
        if(!(StringUtils.equals(exCommand.getExPayChannel(),PayChannel._06.toString()) || StringUtils.equals(exCommand.getExPayChannel(),PayChannel._03.toString()))){
            logger.error("checkExpress payChannel is not support!! for orderId:"+getRequest().getParameter(GOPAY_ORDER_ID));
            throw  new GopayException(ProcCodeConstants.PROC_CODE_100E9002);
        }
        if(StringUtils.isBlank(exCommand.getExMobileNo()) || !mobileNo.matcher(exCommand.getExMobileNo()).matches()){
            throw  new GopayException(ProcCodeConstants.PROC_CODE_100E1053);
        }

        if(StringUtils.isBlank(exCommand.getExIdCardNo()))
            throw  new GopayException(ProcCodeConstants.PROC_CODE_100E1058);

        if(StringUtils.isBlank(exCommand.getExHolder()))
            throw  new GopayException(ProcCodeConstants.PROC_CODE_100E1018);

        if(StringUtils.isBlank(exCommand.getBankCardNo()))
            throw  new GopayException(ProcCodeConstants.PROC_CODE_000E1008);

        if(StringUtils.equals(exCommand.getExPayChannel(),PayChannel._06.toString()) && StringUtils.isBlank(exCommand.getExValidDate())){
            throw  new GopayException(ProcCodeConstants.PROC_CODE_000E1010);
        }

    }

    @RequestMapping("/cbin.shtml")
    @ResponseBody
    public String getExpressCardInfo(String ccardNo){
        JSONObject json = new JSONObject();
        if(StringUtils.isBlank(ccardNo)){
            json.accumulate("cbin", "0");
            return json.toString();
        }
        String bankCode = "";
        ccardNo = ccardNo.replace(" ","").trim();
        EpCardBin bin = epBankCardService.getEpCardBinByCardNo(ccardNo);
        int cbin = 0;//0:不存在 1:不是信用卡 2：信用卡
        if(bin != null){//根据产品要求需要支持贷记卡和准贷记卡
            cbin = ((bin.getCardType() == EpCardType.CREDIT)||(bin.getCardType() == EpCardType.PRECREDIT)) ? 2:1;
            bankCode = bin.getBinBankCode();
            json.accumulate("bankCode", bankCode);
        }
        /**
         * modified by zyt，2017-1-6，对日志中的卡号做掩码。
         */
        logger.info("checkBin:->"+LoggerMaskUtils.maskString(ccardNo)+":"+cbin+"--bankCode:"+bankCode);
        json.accumulate("cbin", cbin+"");

        return json.toString();
    }

    @RequestMapping("/status.shtml")
    @ResponseBody
    public String getExpressCardStatus(String ccardNo) throws GopayException {
        JSONObject json = new JSONObject();
        if(StringUtils.isNotBlank(ccardNo)){

            try {
                ccardNo = decrypt4js(ccardNo);
            } catch (Exception e) {
                logger.error("decrypt4js 失败", e);
                throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002, "decrypt4js 失败");
            }
            ccardNo = ccardNo.replaceAll(" ","");
            boolean res = epBankCardService.isFreezeCardNo(ccardNo);
            /**
             * modified by zyt，2017-1-6，对日志中的卡号做掩码。
             */
            logger.info("checkStatus:->"+LoggerMaskUtils.maskString(ccardNo)+":--status:"+res);
            json.accumulate("sta",res?"1":"0");
        }else{
            json.accumulate("sta","2");
        }
        return json.toString();
    }

    private void validate(CpsGenMainOrder order,ExpressPayChannelCommand exCommand) throws GopayException {
        if (TxnStaCode.TXN_STA_CD_30000.value != (order.getTxnStaCd())) {
            logger.error("订单状态不对！txn_sta_cd wrong!" + order);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5042);
        }

        if(StringUtils.isBlank(exCommand.getExPayBankCode()))
            throw new WebException(ProcCodeConstants.PROC_CODE_100E9002);

        if(StringUtils.isBlank(exCommand.getExPayChannel()))
            throw new WebException(ProcCodeConstants.PROC_CODE_100E9002);

        if(StringUtils.isBlank(exCommand.getBankCardNo()))
            throw new WebException(ProcCodeConstants.PROC_CODE_100E9002);

        boolean res = epBankCardService.isFreezeCardNo(exCommand.getBankCardNo());
        if(res){
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5118);
        }
        //校验收款方
        checkRecvCustStatus(2, order.getMainRecvCustId());
        AcctMastBean acct = acctTransService.getAccount(order.getMainRecvAcct());
        if (null == acct) {
            logger.error("账户不存在,acctId=" + order.getMainRecvAcct());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E6012);
        }
        if (AcctStatus.F.equals(acct.getAccStatus())) {
            if (FrezCode.CRE.equals(acct.getFrezCode()) || FrezCode.FUL.equals(acct.getFrezCode())) {
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E3025, "账户[" + order.getMainRecvAcct()
                        + "]处于冻结状态[" + acct.getFrezCode() + "]，无法入款");
            }
        }
    }

    private void updateOrder(ExpressPayChannelCommand command, CpsGenMainOrder order,String payCustId) throws WebException {
        Map<MainOrderField, String> values = new HashMap<MainOrderField, String>();
        LoginUser loginUser = getLoginUser();
        //计算手续费
        ExpressPoundageVo epv = getPoundageRes(order,command);
        PayChannel payChannel = epv.getPayChannel();
        PoundageRes p = epv.getPoundageRes();
        if(loginUser!=null){
            values.put(MainOrderField.PAY_CUST_ID, loginUser.getUser().getCustId());
            values.put(MainOrderField.PAY_ACCT, command.getExGopayAcctId());
        }else if(StringUtils.isNotBlank(payCustId)){
            values.put(MainOrderField.PAY_CUST_ID, payCustId);
        }
        values.put(MainOrderField.PAY_CHANNEL,payChannel.value);
        values.put(MainOrderField.OUT_STLM_ID, command.getExPayBankCode());
        values.put(MainOrderField.ORDER_DEAL_AMT, p.getOrderDealAmt().toString());
        values.put(MainOrderField.ORDER_REAL_FEE_AMT, p.getOrderRealFeeAmt().toString());
        values.put(MainOrderField.TOTAL_ORDER_AMT, p.getTotalAmt().toString());
        values.put(MainOrderField.TOTAL_ORDER_FEE_AMT, p.getTotalFeeAmt().toString());
        values.put(MainOrderField.ORDER_FEE_PAYER, p.getOrderFeePayer().value);
        values.put(MainOrderField.TXN_STA_CD, TxnStaCode.TXN_STA_CD_30101.value+"");
        
        /**结算金额： 网银付款更新结算金额字段  系统加固   zhg.zhang 20160712 start**/
        values.put(MainOrderField.SETTLE_AMT, p.getSettleAmt().toPlainString());
        /**结算金额： 网银付款更新结算金额字段  系统加固   zhg.zhang 20160712 end**/

        /**远程IP地址 songefengli 20160922**/
        values.put(MainOrderField.REMOTE_IP, RequestUtils.getRemoteRealIpAddr(getRequest()));

        // 如果是收款方承担手续费，且手续费金额大于订单金额，中断交易，防止实际交易金额为负数。
        if (OrderFeePayer.REC_PAYER.equals(p.getOrderFeePayer())) {
            if (1 == p.getTotalFeeAmt().compareTo(order.getMerTxnAmt())) {
                logger.error("手续费金额大于订单金额，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
                        + order.getMerTxnAmt() + "]! " + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5055);
            }
            /*通用分账  added by Chenyu Li at 2018/3/10 start*/
            if(isSplit(order)){
                CpsReceiptSplitDtl cpsReceiptSplitDtl = cpsReceiptSplitDtlQueryDAO.queryPlatformDtlsByGopayOrderId(order.getGopayOrderId());
                if (cpsReceiptSplitDtl == null) {
                    logger.error("平台方没有参与分账，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
                            + order.getMerTxnAmt() + "]! " + command + ", " + order);
                    throw new WebException(ProcCodeConstants.PROC_CODE_100E1033);
                }
                if (1 == p.getTotalFeeAmt().compareTo(cpsReceiptSplitDtl.getMerTxnAmt())) {
                    logger.error("手续费金额大于平台方分账金额，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
                            + order.getMerTxnAmt() + "]! " + command + ", " + order);
                    throw new WebException(ProcCodeConstants.PROC_CODE_100E1405);
                }
            }
            /*通用分账  added by Chenyu Li at 2018/3/10 end*/
//            BigDecimal subAccountAmt = subAccountInfoService.subAccountSumAmt(order);
//            BigDecimal txnAmt = order.getMerTxnAmt().subtract(p.getTotalFeeAmt());
//            if(subAccountAmt.compareTo(txnAmt) >0){
//                logger.error("分账总金额大于订单金额和手续费金额，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
//                        + order.getMerTxnAmt() + "]! " +"subAccountAmt["+subAccountAmt+"]! " + command + ", " + order);
//                throw new WebException(ProcCodeConstants.PROC_CODE_100E1186);
//            }
        }
        // 云账户子账户收款交易如果普通账户可用余额小于手续费，则抛出异常，账户余额不足 add by sh.jiao 20171020
        if(IntTxnCd._01813.value.equals(order.getGopayIntTxnCd())) {
            AcctMastBean acct = acctTransService.getAccount(order.getMainRecvAcct());
            if(acct == null) {
                logger.error("收款账户不存在,gopayOrderId:"+order.getGopayOrderId());
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5260);
            }
            if (new BigDecimal(acct.getAvaAmt()).compareTo(p.getTotalFeeAmt())<0){
                logger.error("手续费金额大于普通账户可用余额，中断交易，支付失败，请联系平台！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>avaAmt["
                        + acct.getAvaAmt() + "]! " + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5344);
            }
        }

        try {
            logger.error("调用cps更新订单状态.BEGIN.call cps update mainOrder." + command + ", " + order + ", " + values);
            mainOrderUpdateService.payUpdate(order.getGopayOrderId(), values);
            logger.error("调用cps更新订单状态.END.call cps update mainOrder." + command + ", " + order);
        } catch (GopayException e) {
            logger.error("调用cps更新订单状态出错！call cps update mainOrder exception!" + command + ", " + order, e);
            throw new WebException(e.getErrCode());
        }
    }


    private String getSmsContent(CpsGenMainOrder order,ExpressPayChannelCommand command){
        String cardNo = command.getBankCardNo().substring(command.getBankCardNo().length()-4);
        String time = DateUtils.getCurrDate("MM月dd日HH:mm");
        String tranAmt = new DecimalFormat("0.00").format(order.getMerTxnAmt());
        String sms = "本次支付国付宝验证码：%s，您的银行卡（尾号"+cardNo+"）于"+time+"申请国付宝快捷支付扣款，支付金额"+tranAmt+"元。请勿将验证码告知他人并确认支付网址为合法网址。如非本人操作请致电：400-055-0009";
        return sms;
    }

    /**
     * 根据身份证号校验是否满十八岁  add by  gaocl
     * @param request 请求
     */
    @RequestMapping("/checkAdult")
    @ResponseBody
    public String check18Age(HttpServletRequest request){
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("result", false);// 操作标识

        String idCardNo = request.getParameter("exIdCardNo");
        if(StringUtils.isNotEmpty(idCardNo)){
            try {
                idCardNo = decrypt4js(idCardNo);
                int year = Integer.parseInt(idCardNo.substring(6, 10));
                int nowDay = Integer.parseInt(new SimpleDateFormat("yyyyMMdd").format(new Date()));
                int adultDate = Integer.parseInt(String.valueOf(year + 18) + idCardNo.substring(10, 14)); //满18岁的日期
                if(idCardNo.length()>15){  //身份证号为15位的则不校验是否满18岁
                    if(adultDate - nowDay > 0){
                        resultMap.put("result", true);// 操作标识
                    }
                }
            } catch (Exception e) {
                logger.error("校验未满18岁出错：",e);
            }
        }
      return JSONObject.fromObject(resultMap).toString();
    }
    
    private String checkAgeToken(String idCardNo){
        if(StringUtils.isNotEmpty(idCardNo)){
            int nowDay = Integer.parseInt(new SimpleDateFormat("yyyyMMdd").format(new Date()));
            int adultDate = 0;
            try {
                int year = Integer.parseInt(idCardNo.substring(6, 10));
                adultDate = Integer.parseInt(String.valueOf(year + 18) + idCardNo.substring(10, 14));
            } catch (Exception e) {
                logger.error("截取身份证出错：",e);
            }
            if(idCardNo.length()>15){
                if(adultDate - nowDay > 0){
                    return "您还未满18周岁，无法继续支付！";
                }
            }
        }
        return null;
    }
}
